[Py-Intro] Aula 01

Instalando Python, introdução a bibliotecas e estruturas de dados

O que você vai aprender nesta aula?

Após o término da aula você terá aprendido:

  • Informações úteis sobre a linguagem Python
  • Instalar o python
  • O que é o Jupyter Notebook, como instalá-lo e rodá-lo
  • Usar o ambiente virtual
  • Instalar bibliotecas
  • Acessar páginas usando Python
  • Estruturas de dados do Python: listas e dicionários

Sobre a linguagem Python

Se você já conhece a linguagem e está animado em aprendê-la já pode seguir para a próxima seção. Se, mesmo assim, você ainda estiver curioso para saber mais sobre Python fique convidado a ler os próximos parágrafos.

Python é uma linguagem simples, enxuta e poderosa. Com poucas linhas e sintaxe clara é possível executar tarefas complexas. Essa característica se dá, pois os tipos de dados de alto nível permitem fazer operações complexas de uma única vez, além de não ser necessário declarar variáveis ou tipos dos argumentos.

Python vem com pilhas inclusas. Em sua biblioteca padrão há soluções para diversos tipos de problemas recorrentes, como:

  • Interface gráfica (tkinter)
  • Internet (requisições HTTP, email, sockets etc.)
  • Data, hora e calendário
  • Acesso a arquivos e pastas
  • Execução de outras aplicações/processos
  • E muito mais: https://docs.python.org/3/library/

A linguagem foi criada em 1991 e desde então vem crescendo constantemente ano a ano, tanto no quesito de número de usuário quanto em atualizações e melhorias do interpretador e da linguagem em si. Atualmente Python está na versão 3.5 que trouxe várias features interessantes que podem ser conferidas aqui.

Muitas empresas como Google, Facebook, Mozilla, Microsoft, Intel, IBM, Globo e Magazine Luiza usam Python em produtos como Instagram, YouTube e o g1 (portal de notícias da globo).

PS: Dica para vida: os patrocinadores de grandes eventos como, por exemplo PyCon 2015 e 2016, usam e estão patrocinando a linguagem. E isso também vale para qualquer outra tecnlogia.

Python é uma linguagem interpretada, ou seja, seu código-fonte executado diretamente pelo interpretador, sem precisar de compilar o programa em instruções de linguagem de máquina.

PS: para agilizar a execução de módulos o interpretador do Python cria caches. Para saber mais, veja: “Compiled” Python files

Por ser interpretada a Python ganha diversas vantagens, como:

  • Ganho de tempo por não precisar compilar/linkar o programa
  • Interpretador pode ser usado de forma interativa tornando possível realizar testes e experimentos
  • Este "caderno" - o jupyter notebook

A linguagem possui 20 príncipios que guiam seu desenvolvimento e podem ser conferidos rodando o seguinte comando:


In [1]:
import this


The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Agora é hora de por as mãos na massa! Vamos do começo:

Instalando o Python 3.5

Caso você já tenha o Python 3.5 siga para a próxima sessão!

Debian e derivados (ubuntu, mint etc.)

$ sudo apt-get install python3.5

Windows e OS X

https://www.python.org/downloads/

Caso você esteja usando o windows não esqueça de marcar a opção: "Add Python.exe to Path", como mostrado na seguinte imagem:

(imagem retirada do [Django Girls Tutorial](http://tutorial.djangogirls.org/pt/))

Virtualenv (Ambiente virtual)

O virtualenv é uma ferramenta que serve para manter as dependências de projetos diferentes em pastas separadas, desse modo é possível trabalhar me um projeto usando, por exemplo, o Django 1.9 enquanto se mantém um projeto antigo que usa a versão 1.5 do framework.

O virtualenv cria uma pasta contendo todas as dependências que um projeto Python necessita.

O virtualenv já vem instalado no Python 3.5, para criar um novo ambiente faça:

Linux e Mac
$ python3.5 -m venv env
Windows

Abra o programa de linha de comando do Windows e digite o comando abaixo. Isso pode ser feito apertando o botão do windows + R, digitando cmd e apertando ENTER.

> C:\Python3.5\python -m venv env

Esse comando criará uma pasta chamada env/ contendo os executáveis do Python e uma cópia do pip para instalar outros pacotes. Vale lembrar que o nome do ambiente virtual env pode ser trocado por qualquer outro.

Para usar o virtualenv é necessário antes que ele seja ativado:

Linux e Mac
$ source env/bin/activate
Windows
> env\Scripts\activate

Para sair de um ambiente virtual use o comando deactivate.

Agora nosso ambiente virtual está pronto para ser usado!

Instalando pacotes com o pip

O pip permite instalar pacotes Python (listados no PyPI: the Python Package Index) de forma fácil. O pip significa "pip install packages" (ou pip instala pacotes).

Por exemplo, vamos instalar a biblioteca requests que usaremos mais para frente nesta aula:

(env) $ pip install requests

Jupyter Notebook

O Jupyter Notebook é uma aplicação web que permite a criação e compatilhamento de documentos (notebooks) que contém código ao vivo, equações, visualizações e textos explanatórios. Ele é muito utilizado para transformação de dados, modelagem estatística, simulação numérica, aprendizado de máquina e ensino.

Para rodá-lo em sua máquina é preciso: instalar, rodar o servidor e acessr pelo navegador! É mais simples do que parece, vamos fazer esses passos.

Instalando

Vamos instalar o jupyter notebook executando o seguinte comando:

(env) $ pip install jupyter[notebook]

No linux

Caso não seja possível instalar o jupyter[notebook] rode:

    $ sudo apt-get install build-essential python3.5-dev
    (env) $ pip install --upgrade pip
    (env) $ pip install jupyter[notebook]

Rodando

Não esqueça de baixar este documento (Aula01.ipynb) e rodar o jupyter notebook na mesma pasta.

Para rodá-lo e tornar possivel o acesso do notebook pelo navegador, execute o seguinte comando:

(env) $ jupyter notebook

Agora é só acessar a página http://localhost:8888/notebooks (que deve ter sido aberta automaticamente) e abrir o notebook Aula01.ipynb que já estamos prontos para codificar!

Para rodar um código específico clique na caixa do código e pressione CTRL+Enter

Acessando páginas web

Nosso primeiro exemplo será criar o código de uma aplicação que nos permite baixar o código-fonte de sites.

Para isso vamos usar a biblioteca requests que foi instalada em um passo anterior (caso você não tenha instalado rode pip install requests).

Primeiro preciamos importar a requests:


In [1]:
import requests

Agora vamos fazer uma requisição HTTP ao Github para baixar o conteúdo do repositório deste curso (através da URL https://github.com/lamenezes/python-intro):


In [2]:
url = 'https://github.com/lamenezes/python-intro'  # não é necessário declarar variáveis em python
response = requests.get(url)  # e nem especificar seu tipo
response.status_code


Out[2]:
200

200 é o código de resposta que informa que a requisição foi bem sucedida (ou OK).

PS: No curso de Desenvolvimento Web com Django será explicado com calma como funciona o protocolo HTTP.

Agora vamos analisar os cabeçalhos dessa resposta:


In [3]:
print(response.headers)


{'Strict-Transport-Security': 'max-age=31536000; includeSubdomains; preload', 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-cache', 'X-Served-By': 'b437fa0c9608399c74bf50b5c3f52799', 'Transfer-Encoding': 'chunked', 'Set-Cookie': 'logged_in=no; domain=.github.com; path=/; expires=Tue, 06 May 2036 01:53:29 -0000; secure; HttpOnly, _gh_sess=eyJzZXNzaW9uX2lkIjoiM2RkNGU5ZTFkMmU5YmE4ZGFmZTEwOTFlNWI5YjEwMzciLCJzcHlfcmVwbyI6ImxhbWVuZXplcy9weXRob24taW50cm8iLCJzcHlfcmVwb19hdCI6MTQ2MjQ5OTYwOSwiX2NzcmZfdG9rZW4iOiJWWHJaMGRBeFZjT0ZDZGtQcDRyd04wZzZ4ZktaRTJENFM0MlJYalJ6dVNVPSIsImZsYXNoIjp7ImRpc2NhcmQiOlsiYW5hbHl0aWNzX2xvY2F0aW9uIl0sImZsYXNoZXMiOnsiYW5hbHl0aWNzX2xvY2F0aW9uIjoiLzx1c2VyLW5hbWU%2BLzxyZXBvLW5hbWU%2BIn19fQ%3D%3D--db707e407a9cbccdacd5c699d8f9c721cfe0668b; path=/; secure; HttpOnly', 'X-Content-Type-Options': 'nosniff', 'X-UA-Compatible': 'IE=Edge,chrome=1', 'Date': 'Fri, 06 May 2016 01:53:29 GMT', 'Server': 'GitHub.com', 'X-XSS-Protection': '1; mode=block', 'Content-Encoding': 'gzip', 'X-Request-Id': '20221edde149239d2d332bace865ce62', 'Vary': 'X-PJAX, Accept-Encoding', 'X-GitHub-Request-Id': 'BADFDA80:6458:5105BD3:572BF919', 'X-Runtime': '0.049845', 'X-Frame-Options': 'deny', 'Public-Key-Pins': 'max-age=5184000; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho="; pin-sha256="k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws="; pin-sha256="K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q="; pin-sha256="IQBnNBEiFuhj+8x6X8XLgh01V9Ic5/V3IRQLNFFc7v4="; pin-sha256="iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0="; pin-sha256="LvRiGEjRqfzurezaWuj8Wie2gyHMrW5Q06LspMnox7A="; includeSubDomains', 'Content-Security-Policy': "default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src render.githubusercontent.com; connect-src 'self' uploads.github.com status.github.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com api.braintreegateway.com client-analytics.braintreegateway.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com; img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com collector.githubapp.com *.gravatar.com *.wp.com checkout.paypal.com *.githubusercontent.com; media-src 'none'; object-src assets-cdn.github.com; plugin-types application/x-shockwave-flash; script-src assets-cdn.github.com; style-src 'unsafe-inline' assets-cdn.github.com", 'Status': '200 OK'}

O atributo headers de response (response.headers) nos trouxe os cabeçalhos em forma de um dicionário (ou dict). O dict é uma estrutura de dados do Python utilizada para armazenar informações na forma de chave e valor envoltas por chaves {}. Dicts serão explicados mais para frente.

Por motivos técnicos a saída foi apresentada em um formato difícil de ler, para melhorá-la podemos fazer um pequeno workaround:


In [4]:
dict(response.headers)


Out[4]:
{'Cache-Control': 'no-cache',
 'Content-Encoding': 'gzip',
 'Content-Security-Policy': "default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src render.githubusercontent.com; connect-src 'self' uploads.github.com status.github.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com api.braintreegateway.com client-analytics.braintreegateway.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com; img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com collector.githubapp.com *.gravatar.com *.wp.com checkout.paypal.com *.githubusercontent.com; media-src 'none'; object-src assets-cdn.github.com; plugin-types application/x-shockwave-flash; script-src assets-cdn.github.com; style-src 'unsafe-inline' assets-cdn.github.com",
 'Content-Type': 'text/html; charset=utf-8',
 'Date': 'Fri, 06 May 2016 01:53:29 GMT',
 'Public-Key-Pins': 'max-age=5184000; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho="; pin-sha256="k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws="; pin-sha256="K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q="; pin-sha256="IQBnNBEiFuhj+8x6X8XLgh01V9Ic5/V3IRQLNFFc7v4="; pin-sha256="iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0="; pin-sha256="LvRiGEjRqfzurezaWuj8Wie2gyHMrW5Q06LspMnox7A="; includeSubDomains',
 'Server': 'GitHub.com',
 'Set-Cookie': 'logged_in=no; domain=.github.com; path=/; expires=Tue, 06 May 2036 01:53:29 -0000; secure; HttpOnly, _gh_sess=eyJzZXNzaW9uX2lkIjoiM2RkNGU5ZTFkMmU5YmE4ZGFmZTEwOTFlNWI5YjEwMzciLCJzcHlfcmVwbyI6ImxhbWVuZXplcy9weXRob24taW50cm8iLCJzcHlfcmVwb19hdCI6MTQ2MjQ5OTYwOSwiX2NzcmZfdG9rZW4iOiJWWHJaMGRBeFZjT0ZDZGtQcDRyd04wZzZ4ZktaRTJENFM0MlJYalJ6dVNVPSIsImZsYXNoIjp7ImRpc2NhcmQiOlsiYW5hbHl0aWNzX2xvY2F0aW9uIl0sImZsYXNoZXMiOnsiYW5hbHl0aWNzX2xvY2F0aW9uIjoiLzx1c2VyLW5hbWU%2BLzxyZXBvLW5hbWU%2BIn19fQ%3D%3D--db707e407a9cbccdacd5c699d8f9c721cfe0668b; path=/; secure; HttpOnly',
 'Status': '200 OK',
 'Strict-Transport-Security': 'max-age=31536000; includeSubdomains; preload',
 'Transfer-Encoding': 'chunked',
 'Vary': 'X-PJAX, Accept-Encoding',
 'X-Content-Type-Options': 'nosniff',
 'X-Frame-Options': 'deny',
 'X-GitHub-Request-Id': 'BADFDA80:6458:5105BD3:572BF919',
 'X-Request-Id': '20221edde149239d2d332bace865ce62',
 'X-Runtime': '0.049845',
 'X-Served-By': 'b437fa0c9608399c74bf50b5c3f52799',
 'X-UA-Compatible': 'IE=Edge,chrome=1',
 'X-XSS-Protection': '1; mode=block'}

Para acessar um cabeçalho específico por sua chave fazemos:


In [5]:
response.headers['content-type']


Out[5]:
'text/html; charset=utf-8'

In [6]:
response.headers['date']


Out[6]:
'Fri, 06 May 2016 01:53:29 GMT'

In [7]:
response.text[:1000]  # retorna os 1000 primeiros caracteres do conteúdo da resposta


Out[7]:
'\n\n\n\n<!DOCTYPE html>\n<html lang="en" class="">\n  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">\n    <meta charset=\'utf-8\'>\n\n    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-64d9cf09923fe989623ec42695fc7653a16513c1a63441ee66f4b81ef555ae49.css" media="all" rel="stylesheet" />\n    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-7d5c7e87c2f34802bf90a223dbdaf4f7a2511aa5c3dd80c7bc2ad86f36e0ac56.css" media="all" rel="stylesheet" />\n    \n    \n    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-d2013a78fb2b0b2d9afce49f4cf82965d3f075b6b021bf51aa28d8df766f2ba4.css" media="all" rel="stylesheet" />\n    \n\n    <link as="script" href="https://assets-cdn.github.com/assets/frameworks-a7834ad5e30f73a7017adee72b9e733ae5574cf80cb92924a384d22d72a836e1.js" rel="preload" />\n    \n    <link as="s'

Como visto anteriormente a biblioteca requests permite o envio de requisições HTTP de maneira extremamante fácil. Para obter mais informações sobre a requests acesse a doumentação oficial.

Agora que já aprendemos o básico podemos partir para um exemplo mais interessante.

Acessando os dados da API do github

O Github oferece uma API que fornece dados de seus repositórios públicos. São dadas informações como quantos projetos estão cadastrados na plataforma, quantos contribuidores trabalharam em quais repositórios, a quais organizações essas fazem parte e muito mais. (mais informações na documentação oficial)

O acesso aos dados dessa API é feito através do envio de requisições HTTP para diferentes caminhos na URL base https://api.github.com/. Caso você queira testar a API, pode acessar o link anterior pelo navegador e mudar a URL manualmente, porém nosso foco aqui será usar a biblioteca requests para pegar esses dados.

Todas as respostas da API são em formato JSON. O JSON siginifca JavaScript Object Notation e pronuncia-se "djêizon" e é um formato fácil de processar e simples de utilizar. Para mais informações sobre o JSON acesse a página oficial. Falaremos mais sobre JSON no decorrer do curso, mas fique tranquilo que não segredo há algum nesse assunto.

Vamos testar a API e pegar os repositórios de um usuário específico através da URL https://api.github.com/users/lamenezes/repos:


In [8]:
response = requests.get('https://api.github.com/users/lamenezes/repos')
response.status_code


Out[8]:
200

In [9]:
response.text[:1000]  # pegando os primeiros 1000 caracters do conteúdo da resposta


Out[9]:
'[{"id":42411070,"name":"Adafruit_Python_CharLCD","full_name":"lamenezes/Adafruit_Python_CharLCD","owner":{"login":"lamenezes","id":3208493,"avatar_url":"https://avatars.githubusercontent.com/u/3208493?v=3","gravatar_id":"","url":"https://api.github.com/users/lamenezes","html_url":"https://github.com/lamenezes","followers_url":"https://api.github.com/users/lamenezes/followers","following_url":"https://api.github.com/users/lamenezes/following{/other_user}","gists_url":"https://api.github.com/users/lamenezes/gists{/gist_id}","starred_url":"https://api.github.com/users/lamenezes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lamenezes/subscriptions","organizations_url":"https://api.github.com/users/lamenezes/orgs","repos_url":"https://api.github.com/users/lamenezes/repos","events_url":"https://api.github.com/users/lamenezes/events{/privacy}","received_events_url":"https://api.github.com/users/lamenezes/received_events","type":"User","site_admin":false},"private":'

A resposta trouxe todos os repositórios do usuário lamenezes em uma string no padrão JSON.

Essa string não é interessante para nós, pois é difícil acessar dados específicos do JSON através dela. Seria muito melhor para nós se essa resposta fosse traduzida para um dicionário do Python (que possui sintaxe muito parecida com o JSON).

Normalmente teríamos que importar a biblioteca json e realizar a conversão, no pior caso poderia ser necessário escrever um parser específico para tratar casos especiais.

No entanto, a biblioteca requests já faz esse trabalho para nós:


In [10]:
repositorios = response.json()
repo = repositorios[0]  # pegando apenas o primeiro repositório por brevidade
repo


Out[10]:
{'archive_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/{archive_format}{/ref}',
 'assignees_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/assignees{/user}',
 'blobs_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/git/blobs{/sha}',
 'branches_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/branches{/branch}',
 'clone_url': 'https://github.com/lamenezes/Adafruit_Python_CharLCD.git',
 'collaborators_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/collaborators{/collaborator}',
 'comments_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/comments{/number}',
 'commits_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/commits{/sha}',
 'compare_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/compare/{base}...{head}',
 'contents_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/contents/{+path}',
 'contributors_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/contributors',
 'created_at': '2015-09-13T20:08:52Z',
 'default_branch': 'master',
 'deployments_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/deployments',
 'description': 'Python library for accessing Adafruit character LCDs from a Raspberry Pi or BeagleBone Black.',
 'downloads_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/downloads',
 'events_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/events',
 'fork': True,
 'forks': 0,
 'forks_count': 0,
 'forks_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/forks',
 'full_name': 'lamenezes/Adafruit_Python_CharLCD',
 'git_commits_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/git/commits{/sha}',
 'git_refs_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/git/refs{/sha}',
 'git_tags_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/git/tags{/sha}',
 'git_url': 'git://github.com/lamenezes/Adafruit_Python_CharLCD.git',
 'has_downloads': True,
 'has_issues': False,
 'has_pages': False,
 'has_wiki': True,
 'homepage': None,
 'hooks_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/hooks',
 'html_url': 'https://github.com/lamenezes/Adafruit_Python_CharLCD',
 'id': 42411070,
 'issue_comment_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/issues/comments{/number}',
 'issue_events_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/issues/events{/number}',
 'issues_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/issues{/number}',
 'keys_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/keys{/key_id}',
 'labels_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/labels{/name}',
 'language': 'Python',
 'languages_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/languages',
 'merges_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/merges',
 'milestones_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/milestones{/number}',
 'mirror_url': None,
 'name': 'Adafruit_Python_CharLCD',
 'notifications_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/notifications{?since,all,participating}',
 'open_issues': 0,
 'open_issues_count': 0,
 'owner': {'avatar_url': 'https://avatars.githubusercontent.com/u/3208493?v=3',
  'events_url': 'https://api.github.com/users/lamenezes/events{/privacy}',
  'followers_url': 'https://api.github.com/users/lamenezes/followers',
  'following_url': 'https://api.github.com/users/lamenezes/following{/other_user}',
  'gists_url': 'https://api.github.com/users/lamenezes/gists{/gist_id}',
  'gravatar_id': '',
  'html_url': 'https://github.com/lamenezes',
  'id': 3208493,
  'login': 'lamenezes',
  'organizations_url': 'https://api.github.com/users/lamenezes/orgs',
  'received_events_url': 'https://api.github.com/users/lamenezes/received_events',
  'repos_url': 'https://api.github.com/users/lamenezes/repos',
  'site_admin': False,
  'starred_url': 'https://api.github.com/users/lamenezes/starred{/owner}{/repo}',
  'subscriptions_url': 'https://api.github.com/users/lamenezes/subscriptions',
  'type': 'User',
  'url': 'https://api.github.com/users/lamenezes'},
 'private': False,
 'pulls_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/pulls{/number}',
 'pushed_at': '2015-09-13T20:10:42Z',
 'releases_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/releases{/id}',
 'size': 100,
 'ssh_url': 'git@github.com:lamenezes/Adafruit_Python_CharLCD.git',
 'stargazers_count': 0,
 'stargazers_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/stargazers',
 'statuses_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/statuses/{sha}',
 'subscribers_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/subscribers',
 'subscription_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/subscription',
 'svn_url': 'https://github.com/lamenezes/Adafruit_Python_CharLCD',
 'tags_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/tags',
 'teams_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/teams',
 'trees_url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD/git/trees{/sha}',
 'updated_at': '2015-09-13T20:08:53Z',
 'url': 'https://api.github.com/repos/lamenezes/Adafruit_Python_CharLCD',
 'watchers': 0,
 'watchers_count': 0}

A resposta nos trouxe uma lista de dicionários com as informações dos repositórios do usuário lamenezes. Agora fica a dúvida: o que exatamente é uma lista e um dicionário?

Listas

Listas, como o próprio nome sugere, são estruturas de dados mutáveis que armanzenam listas de valores. Os valores da lista são acessados pelo número relativo a sua posição.

Ao invés de gastar dedos digitando mais sobre o que é uma lista é mais fácil demonstrá-la:


In [11]:
numeros = [1, 2.5, 3, 4.5, 5]
numeros


Out[11]:
[1, 2.5, 3, 4.5, 5]

In [12]:
numeros[0]


Out[12]:
1

In [13]:
numeros[3]


Out[13]:
4.5

In [14]:
numeros[-1]  # -1 acessa o último elemento da lista!


Out[14]:
5

Listas podem armazenar qualquer tipo de dados:


In [15]:
lista = ['foobar', False, ['a', 'b', 'c'], {'foo': 'bar'}, 10, -0.5]
lista


Out[15]:
['foobar', False, ['a', 'b', 'c'], {'foo': 'bar'}, 10, -0.5]

Fazemos assim para verificar se um elemento faz parte de uma lista:


In [16]:
'foobar' in lista


Out[16]:
True

In [17]:
'abc' in lista


Out[17]:
False

In [18]:
-0.5 in lista


Out[18]:
True

Para saber o tamanho de uma lista basta usar a função len():


In [19]:
len(lista)


Out[19]:
6

In [20]:
len(lista[2])  # o segundo elemento da lista é uma lista com 3 elementos!


Out[20]:
3

In [21]:
len(numeros)


Out[21]:
5

Para remover elementos de uma lista existe a palavra reservada del que é utilizada assim:


In [22]:
lista


Out[22]:
['foobar', False, ['a', 'b', 'c'], {'foo': 'bar'}, 10, -0.5]

In [23]:
del lista[3]
lista


Out[23]:
['foobar', False, ['a', 'b', 'c'], 10, -0.5]

In [24]:
del lista[-1]  # remove último elemento
lista


Out[24]:
['foobar', False, ['a', 'b', 'c'], 10]

Iterar uma lista é simples:


In [25]:
for numero in numeros:
    print(numero)


1
2.5
3
4.5
5

O for do Python, diferentemente de outras linguagens como C e Java, faz o controle dos índices internamente.

Vamos fazer mais um exemplo para deixar claro:


In [26]:
numeros = range(1, 11)  # cria uma lista de números de 1 a 10
list(numeros)


Out[26]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [27]:
for numero in numeros:
    print(numero ** 2)  # numero elevado a segunda potência


1
4
9
16
25
36
49
64
81
100

A função range(inicio, fim) cria listas de valores no intervalo de inicio até fim - 1. Ao lidar com intervalos no python o primeiro número é sempre incluso e o último excluído. Segue alguns exemplos de uso da função range()


In [28]:
list(range(10))  # números de 0 a 9


Out[28]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [29]:
list(range(10, 20))  # números de 10 a 19


Out[29]:
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

In [30]:
list(range(10, 21))  # números de 10 a 20


Out[30]:
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Exercício

Crie uma lista de números de 2 a 8 e imprima cada número vezes pi. Substiua os ... por código python.


In [ ]:
from math import pi

numeros = ...  # crie a lista de números de 2 a 8
for numero in numeros:
    print( ... )  # imprime o número vezes pi

Exercicio

Crie uma lista de preços de produtos em dólar (somente números) e imprima seu valor convertido para reais.


In [ ]:
taxa_dolar = 3.53  # mude esse valor caso o valor do dólar tenha mudado
preços = ...  # python 3 permite declarar variáveis com acentos
for preço in preço:
    print(...)

Dicionários

Dicionários são estruturas de dados utilizadas para armazenar conjuntos de chaves e valores. Em algumas linguagens também são conhecidos como mapaemento.

A diferança de uso entre lista e dicionáro é que o último é acessado por chaves e não pela posição. As chaves podem ser inteiros, strings, booleanos e tuplas (este será visto na próxima aula).

A seguir temos alguns simples exemplos de uso de diconários.

Criar um dict é simples:


In [32]:
notas = {'joao': 5, 'maria': 9, 'ana': 7}
notas


Out[32]:
{'ana': 7, 'joao': 5, 'maria': 9}

Para acessar os elementos basta usar sua chave:


In [33]:
notas['ana']


Out[33]:
7

In [34]:
notas['joao']


Out[34]:
5

Para alterar algum valor fazemos:


In [35]:
notas['joao'] = 6.5
notas


Out[35]:
{'ana': 7, 'joao': 6.5, 'maria': 9}

In [36]:
notas['ana'] = 7.5
notas


Out[36]:
{'ana': 7.5, 'joao': 6.5, 'maria': 9}

Verificamos se uma chave existe no dicionário da seguinte maneira:


In [37]:
'joao' in notas  # verifica se o valor é uma chave do dicionário


Out[37]:
True

In [38]:
'joana' in notas


Out[38]:
False

In [39]:
'ana' in notas


Out[39]:
True

Para acessar somente as chaves fazemos:


In [40]:
list(notas.keys())


Out[40]:
['maria', 'joao', 'ana']

Para acessar somente os valores:


In [41]:
list(notas.values())


Out[41]:
[9, 6.5, 7.5]

Para ter uma lista contendo as chaves e valores:


In [42]:
list(notas.items())


Out[42]:
[('maria', 9), ('joao', 6.5), ('ana', 7.5)]

Para iterar dicionáros é preciso ter cuidado. Por padrão as chaves do dicionário são iteradas:


In [43]:
for chave in notas:
    print(chave)


maria
joao
ana

Caso você queira imprimir os valores é preciso usar notas.values():


In [44]:
for valor in notas.values():
    print(valor)


9
6.5
7.5

Para iterar tanto a chave quanto o valor use a função notas.items() como mostrado a seguir:


In [45]:
for chave, valor in notas.items():
    print(chave, valor)


maria 9
joao 6.5
ana 7.5

Para ficar mais claro podemos mudar os nomes das variáveis e para ficar mais inteligível formatar a saída:


In [46]:
for nome, nota in notas.items():
    print('{0} tirou {1}.'.format(nome.capitalize(), nota))


Maria tirou 9.
Joao tirou 6.5.
Ana tirou 7.5.

In [47]:
list(notas.items())


Out[47]:
[('maria', 9), ('joao', 6.5), ('ana', 7.5)]

Como visto acima o notas.items() retorna uma lista de chaves e valores. Por esse motivo a cada iteração temos acesso a cada chave e valor do dicionário notas, tornando possível essa iteração mais simples e semântica.

Agora que já temos uma noção das estruturas de dados utilizadas, podemos continuar a visualizar as informações dos repositórios do github:

PS: relaxe, pois nas próximas aulas veremos a fundo essas estruturas!

De volta à API do github

Anteriormente realizamos uma requisição à API do github para pegar os repositórios do usuário lamenezes e armazenamos a resposta na variável response. Essa variável ainda está disponível para nós, o que nos permite continuar nosso exemplo anterior:


In [48]:
repositorios = response.json()  # lista de dicionários com dados de cada repositório
repo = repositorios[11]  # vamos analisar o décimo primeiro repositório
repo


Out[48]:
{'archive_url': 'https://api.github.com/repos/lamenezes/dotfiles/{archive_format}{/ref}',
 'assignees_url': 'https://api.github.com/repos/lamenezes/dotfiles/assignees{/user}',
 'blobs_url': 'https://api.github.com/repos/lamenezes/dotfiles/git/blobs{/sha}',
 'branches_url': 'https://api.github.com/repos/lamenezes/dotfiles/branches{/branch}',
 'clone_url': 'https://github.com/lamenezes/dotfiles.git',
 'collaborators_url': 'https://api.github.com/repos/lamenezes/dotfiles/collaborators{/collaborator}',
 'comments_url': 'https://api.github.com/repos/lamenezes/dotfiles/comments{/number}',
 'commits_url': 'https://api.github.com/repos/lamenezes/dotfiles/commits{/sha}',
 'compare_url': 'https://api.github.com/repos/lamenezes/dotfiles/compare/{base}...{head}',
 'contents_url': 'https://api.github.com/repos/lamenezes/dotfiles/contents/{+path}',
 'contributors_url': 'https://api.github.com/repos/lamenezes/dotfiles/contributors',
 'created_at': '2013-12-13T13:49:10Z',
 'default_branch': 'master',
 'deployments_url': 'https://api.github.com/repos/lamenezes/dotfiles/deployments',
 'description': 'My dotfiles',
 'downloads_url': 'https://api.github.com/repos/lamenezes/dotfiles/downloads',
 'events_url': 'https://api.github.com/repos/lamenezes/dotfiles/events',
 'fork': False,
 'forks': 1,
 'forks_count': 1,
 'forks_url': 'https://api.github.com/repos/lamenezes/dotfiles/forks',
 'full_name': 'lamenezes/dotfiles',
 'git_commits_url': 'https://api.github.com/repos/lamenezes/dotfiles/git/commits{/sha}',
 'git_refs_url': 'https://api.github.com/repos/lamenezes/dotfiles/git/refs{/sha}',
 'git_tags_url': 'https://api.github.com/repos/lamenezes/dotfiles/git/tags{/sha}',
 'git_url': 'git://github.com/lamenezes/dotfiles.git',
 'has_downloads': True,
 'has_issues': True,
 'has_pages': False,
 'has_wiki': True,
 'homepage': '',
 'hooks_url': 'https://api.github.com/repos/lamenezes/dotfiles/hooks',
 'html_url': 'https://github.com/lamenezes/dotfiles',
 'id': 15164551,
 'issue_comment_url': 'https://api.github.com/repos/lamenezes/dotfiles/issues/comments{/number}',
 'issue_events_url': 'https://api.github.com/repos/lamenezes/dotfiles/issues/events{/number}',
 'issues_url': 'https://api.github.com/repos/lamenezes/dotfiles/issues{/number}',
 'keys_url': 'https://api.github.com/repos/lamenezes/dotfiles/keys{/key_id}',
 'labels_url': 'https://api.github.com/repos/lamenezes/dotfiles/labels{/name}',
 'language': 'Python',
 'languages_url': 'https://api.github.com/repos/lamenezes/dotfiles/languages',
 'merges_url': 'https://api.github.com/repos/lamenezes/dotfiles/merges',
 'milestones_url': 'https://api.github.com/repos/lamenezes/dotfiles/milestones{/number}',
 'mirror_url': None,
 'name': 'dotfiles',
 'notifications_url': 'https://api.github.com/repos/lamenezes/dotfiles/notifications{?since,all,participating}',
 'open_issues': 0,
 'open_issues_count': 0,
 'owner': {'avatar_url': 'https://avatars.githubusercontent.com/u/3208493?v=3',
  'events_url': 'https://api.github.com/users/lamenezes/events{/privacy}',
  'followers_url': 'https://api.github.com/users/lamenezes/followers',
  'following_url': 'https://api.github.com/users/lamenezes/following{/other_user}',
  'gists_url': 'https://api.github.com/users/lamenezes/gists{/gist_id}',
  'gravatar_id': '',
  'html_url': 'https://github.com/lamenezes',
  'id': 3208493,
  'login': 'lamenezes',
  'organizations_url': 'https://api.github.com/users/lamenezes/orgs',
  'received_events_url': 'https://api.github.com/users/lamenezes/received_events',
  'repos_url': 'https://api.github.com/users/lamenezes/repos',
  'site_admin': False,
  'starred_url': 'https://api.github.com/users/lamenezes/starred{/owner}{/repo}',
  'subscriptions_url': 'https://api.github.com/users/lamenezes/subscriptions',
  'type': 'User',
  'url': 'https://api.github.com/users/lamenezes'},
 'private': False,
 'pulls_url': 'https://api.github.com/repos/lamenezes/dotfiles/pulls{/number}',
 'pushed_at': '2016-03-21T01:07:30Z',
 'releases_url': 'https://api.github.com/repos/lamenezes/dotfiles/releases{/id}',
 'size': 65,
 'ssh_url': 'git@github.com:lamenezes/dotfiles.git',
 'stargazers_count': 3,
 'stargazers_url': 'https://api.github.com/repos/lamenezes/dotfiles/stargazers',
 'statuses_url': 'https://api.github.com/repos/lamenezes/dotfiles/statuses/{sha}',
 'subscribers_url': 'https://api.github.com/repos/lamenezes/dotfiles/subscribers',
 'subscription_url': 'https://api.github.com/repos/lamenezes/dotfiles/subscription',
 'svn_url': 'https://github.com/lamenezes/dotfiles',
 'tags_url': 'https://api.github.com/repos/lamenezes/dotfiles/tags',
 'teams_url': 'https://api.github.com/repos/lamenezes/dotfiles/teams',
 'trees_url': 'https://api.github.com/repos/lamenezes/dotfiles/git/trees{/sha}',
 'updated_at': '2016-02-24T17:20:29Z',
 'url': 'https://api.github.com/repos/lamenezes/dotfiles',
 'watchers': 3,
 'watchers_count': 3}

In [49]:
repo['full_name']


Out[49]:
'lamenezes/dotfiles'

In [50]:
repo['description']


Out[50]:
'My dotfiles'

In [51]:
repo['created_at']  # data de criação


Out[51]:
'2013-12-13T13:49:10Z'

In [52]:
repo['html_url']  # URL da página principal do repositório


Out[52]:
'https://github.com/lamenezes/dotfiles'

Também temos os dados do dono (owner) do repositório:


In [53]:
dono = repo['owner']
dono['login']


Out[53]:
'lamenezes'

'owner' é um dicionário dentro do dicionário do repositório (sim, é possível guardar dicionários dentro de dicionários)

Também podemos acessar as informações diretamente sem recorrer à variável intermediária dono:


In [54]:
repo['owner']['login']


Out[54]:
'lamenezes'

Exercicios

  • Quantos repositórios o usuário lamenezes possui?

Lembrando que esses repositórios estão armazenados na lista repositorios


In [ ]:
# digite o código aqui
  • Imprima as URLs de todos os repositórios

In [ ]:
# digite o código aqui

Para os próximos exercícios será necessáro pegar os repositórios do usuário gvanrossum. Use a biblioteca requests e faça uma requição à API do github (https://api.github.com/) como demostrado anteriormente.


In [ ]:
response = ...
response.status_code  # status_code deve ser 200

Agora pegue o conteúdo da resposta em formato JSON e atribua à variável repos:


In [ ]:
repos = ...
len(repos)  # esta linha deve retornar 5
  • Imprima o nome e descrição de todos os repositórios do gvanrossum:

In [4]:
import requests

response = requests.get('https://api.github.com/users/gvanrossum/repos')
repositorios = response.json()
for repositorio in repositorios:
    print(repositorio['full_name'], repositorio['description'])


(u'gvanrossum/500lines', u'500 Lines or Less')
(u'gvanrossum/asyncio', u'This project is the asyncio module for Python 3.3. Since Python 3.4, asyncio is part of the standard library.')
(u'gvanrossum/ballot-box', u'Automatically exported from code.google.com/p/ballot-box')
(u'gvanrossum/mypy', u'Optional static typing for Python')
(u'gvanrossum/path-pep', u'PEP for a file system path protocol in Python')
(u'gvanrossum/pyxl3', u'A Python 3 extension for writing structured and reusable inline HTML.')
  • Quantos forks o repositório gvanrossum/asyncio possui?

In [ ]:
# digite o código aqui
  • Qual o link do perfil do dono dos repositórios?

In [ ]:
# digite o código aqui

Última pergunta:

  • Quem é gvanrossum?

Fim da Aula 01